import { IPoolable, Pool } from "../drongo-ts";
import { SparseSet } from "./SparseSet";



/**
 * 关联存储
 */
export class Storage<TKey, TValue extends IPoolable> {
    /**
     * entity与内部ID映射 
     */
    private __uid_mapping: Map<TKey, number>;
    /**
     * 稀疏集合
     */
    private __sparse_set: SparseSet;
    /**
     * 数据集
     */
    private __values: Map<new () => TValue, Array<TValue | null>>;
    /**
     * 数据池
     */
    private __valuePools: Map<new () => TValue, Pool<TValue>>;
    /**
     * key关联数据集
     */
    private __sets: Array<Set<new () => TValue>>;
    /**
     * 空闲id
     */
    private __frees: Array<number>;
    /**
     * 当前数据索引
     */
    private __value_idx: number = 0;

    constructor(max_count: number) {
        this.__uid_mapping = new Map<TKey, number>();
        this.__sparse_set = new SparseSet(max_count);
        this.__values = new Map<new () => TValue, Array<TValue | null>>();
        this.__valuePools = new Map<new () => TValue, Pool<TValue>>();
        this.__sets = new Array<Set<new () => TValue>>(max_count);
        this.__frees = [];
    }

    /**
     * 添加
     * @param id 
     */
    add(id: TKey): void {
        if (this.__uid_mapping.has(id)) {
            throw new Error("id already exists");
        }
        let e: number;
        if (this.__frees.length > 0) {
            e = this.__frees.pop()!;
        } else {
            e = this.__value_idx;
            this.__value_idx++;
        }
        this.__uid_mapping.set(id, e);
        this.__sparse_set.add(e);
        const idx = this.__sparse_set.getPackIdx(e);
        if (this.__sets[idx] == null) {
            this.__sets[idx] = new Set<new () => TValue>();
        }
    }

    /**
     * 删除
     * @param id 
     */
    remove(id: TKey): void {
        if (!this.__uid_mapping.has(id)) {
            throw new Error("id not exists");
        }
        const e = this.__uid_mapping.get(id)!;
        let last_e = this.__sparse_set.end;
        let del_idx = this.__sparse_set.getPackIdx(e);
        let last_idx = this.__sparse_set.getPackIdx(last_e);
        //删除关联值
        let list = Array.from(this.__sets[del_idx]);
        while (list.length > 0) {
            const type = list.pop()!;
            this.removeValue(id, type);
        }
        //如果删除的内容不在末尾，则将末尾内容移动到删除的位置
        if (del_idx !== last_idx) {
            let last_set = this.__sets[last_idx];
            for (const type of last_set) {
                const values = this.__values.get(type);
                values[del_idx] = values[last_idx];
                values[last_idx] = null;
            }
            //copy
            last_set.forEach(type => {
                this.__sets[del_idx].add(type);
            });
            last_set.clear();
        }
        this.__uid_mapping.delete(id);
        this.__sparse_set.remove(e);
        this.__frees.push(e);
    }

    /**
     * 是否包含
     * @param id 
     * @returns 
     */
    has(id: TKey): boolean {
        return this.__uid_mapping.has(id);
    }

    /**
     * 获取关联数据
     * @param id   
     * @param type 关联数据类型
     * @returns 
     */
    getValue(id: TKey, type: new () => TValue): TValue | null {
        if (!this.__uid_mapping.has(id)) {
            return null;
        }
        let e = this.__uid_mapping.get(id)!;
        let idx = this.__sparse_set.getPackIdx(e);
        if (idx == this.__sparse_set.invalid) {
            return null;
        }
        let list = this.__values.get(type);
        if (list == null || list.length == 0 || idx >= list.length) {
            return null;
        }
        return list[idx];
    }

    /**
     * 添加关联数据
     * @param id 
     * @param type 
     * @returns 
     */
    addValue(id: TKey, type: new () => TValue): TValue {
        if (!this.__uid_mapping.has(id)) {
            throw new Error("id not exists");
        }
        let e = this.__uid_mapping.get(id)!;
        let idx = this.__sparse_set.getPackIdx(e);
        let list = this.__values.get(type);
        if (list == null) {
            list = new Array<TValue | null>(this.__sparse_set.max_count);
            this.__values.set(type, list);
        }
        if (list[idx] != null) {
            throw new Error("value already exists");
        }
        let pool = this.__valuePools.get(type);
        if (!pool) {
            pool = new Pool(type);
            this.__valuePools.set(type, pool);
        }
        //增加关联数据
        let set = this.__sets[idx];
        set.add(type);
        return pool.alloc();
    }

    /**
     * 是否包含关联数据
     * @param id 
     * @param type 
     * @returns 
     */
    hasValue(id: TKey, type: new () => TValue): boolean {
        if (!this.__uid_mapping.has(id)) {
            return false;
        }
        let e = this.__uid_mapping.get(id)!;
        let idx = this.__sparse_set.getPackIdx(e);
        let list = this.__values.get(type);
        if (list == null || list.length == 0 || idx >= list.length) {
            return false;
        }
        return list[idx] != null;
    }

    /**
     * 删除关联数据
     * @param id 
     * @param type 
     * @returns 
     */
    removeValue(id: TKey, type: new () => TValue): void {
        if (!this.__uid_mapping.has(id)) {
            throw new Error("id not exists");
        }
        let e = this.__uid_mapping.get(id)!;
        let idx = this.__sparse_set.getPackIdx(e);
        let list = this.__values.get(type);
        if (list == null || list.length == 0 || idx >= list.length) {
            throw new Error("value not exists");
        }
        let value = list[idx];
        if (value == null) {
            throw new Error("value not exists");
        }
        list[idx] = null;
        let pool = this.__valuePools.get(type);
        if (!pool) {
            throw new Error("pool not exists");
        }
        pool.recycle(value);
        //删除关联数据
        let set = this.__sets[idx];
        set.delete(type);
    }

    /**
     * 获取数据列表
     * @param type 
     * @returns 
     */
    getValues(type: new () => TValue): Array<TValue> {
        let pool = this.__valuePools.get(type);
        if (pool != null) {
            return pool.elements;
        }
        return null;
    }

    /**
     * 清理
     */
    clear(): void {
        this.__frees.splice(0, this.__frees.length);
        this.__value_idx = 0;
        let del_list = [];
        for (let [key, value] of this.__uid_mapping.entries()) {
            del_list.push(key);
        }
        this.__uid_mapping.clear();
        for (const e of del_list) {
            this.remove(e);
        }
        this.__frees.splice(0, this.__frees.length);
        this.__values.clear();
    }

    /**
     * 销毁
     */
    destroy(): void {
        this.__sets.splice(0, this.__sets.length);
        this.__sets = null;
        this.__uid_mapping.clear();
        this.__uid_mapping = null;
        this.__sparse_set.destory();
        this.__valuePools.clear();
        this.__valuePools = null;
        this.__values.clear();
        this.__values = null;
    }

    /**
     * 获取所有key
     */
    getKeys(result: Array<TKey>): Array<TKey> {
        result = result || [];
        result.push(...this.__uid_mapping.keys());
        return result;
    }

    /**
     * 获取entity的关联数据
     * @param id 
     * @returns 
     */
    getEntitySet(id:TKey):Set<new () => TValue>{
        if (!this.__uid_mapping.has(id)) {
            return null;
        }
        let e = this.__uid_mapping.get(id)!;
        let idx = this.__sparse_set.getPackIdx(e);
        return this.__sets[idx];
    }

    /**
     * 获取所有value
     */
    get values(): Map<new () => TValue, Array<TValue>> {
        return this.__values;
    }
}